package org.fat.nred.actd.tenant.config;

import cn.hutool.core.util.StrUtil;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.fat.nred.actd.tenant.constant.GlobalConstant;
import org.fat.nred.actd.tenant.dto.TenantDatasourceDTO;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.Map;

/**
 * 自定义一个数据源
 */
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
     * 用于保存租户key和数据源的映射关系，目标数据源map的拷贝
     */
    public Map<Object, Object> backupTargetDataSources;

    /**
     * 动态数据源构造器
     *
     * @param defaultDataSource 默认数据源
     * @param targetDataSource  目标数据源映射
     */
    public DynamicDataSource(DataSource defaultDataSource, Map<Object, Object> targetDataSource) {
        backupTargetDataSources = targetDataSource;
        super.setDefaultTargetDataSource(defaultDataSource);
        // 存放数据源的map
        super.setTargetDataSources(backupTargetDataSources);
        // afterPropertiesSet 的作用很重要，它负责解析成可用的目标数据源
        super.afterPropertiesSet();
    }

    /**
     * 必须实现其方法
     * 动态数据源类集成了Spring提供的AbstractRoutingDataSource类，AbstractRoutingDataSource
     * 中获取数据源的方法就是 determineTargetDataSource，而此方法又通过 determineCurrentLookupKey 方法获取查询数据源的key
     * 通过key在resolvedDataSources这个map中获取对应的数据源，resolvedDataSources的值是由afterPropertiesSet()这个方法从
     * TargetDataSources获取的
     *
     * @return lookupKey
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDBType();
    }

    /**
     * 添加数据源到目标数据源map中
     *
     * @param datasource 数据源对象
     */
    public void addDataSource(TenantDatasourceDTO datasource) {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(datasource.getJdbcUrl());
        dataSource.setUsername(datasource.getUsername());
        dataSource.setPassword(datasource.getPassword());
        dataSource.setMaximumPoolSize(100);
        dataSource.setMinimumIdle(10);
        dataSource.setConnectionTimeout(5000);
        dataSource.setConnectionTestQuery("SELECT 1");
        dataSource.setIdleTimeout(60 * 1000);
        dataSource.setMaxLifetime(10 * 60 * 1000);
        // 将传入的数据源对象放入动态数据源类的静态map中，然后再讲静态map重新保存进动态数据源中
        backupTargetDataSources.put(datasource.getTenantKey(), dataSource);
        super.setTargetDataSources(backupTargetDataSources);
        super.afterPropertiesSet();
    }

    /**
     * 是否存在租户key
     *
     * @param tenantKey 租户key
     */
    public Boolean existTenantKey(String tenantKey) {
        if (StrUtil.isEmpty(tenantKey)) {
            return false;
        }
        return backupTargetDataSources.containsKey(tenantKey);
    }

    /**
     * 切换租户
     *
     * @param tenantKey 租户key
     */
    public void switchTenant(String tenantKey) {
        log.info("切换租户：{},当前线程名称:{}", DataSourceContextHolder.getDBType(), Thread.currentThread().getName());
        DataSourceContextHolder.setDBType(tenantKey);
    }

    /**
     * 切换到默认租户信息
     */
    public void switchDefaultTenant() {
        if (GlobalConstant.TENANT_CONFIG_KEY.equals(DataSourceContextHolder.getDBType())) {
            return;
        }
        switchTenant(GlobalConstant.TENANT_CONFIG_KEY);
    }

}
